Vue 源码解析之AST抽象语法树 |
您所在的位置:网站首页 › vue vdom源码 › Vue 源码解析之AST抽象语法树 |
在模板语法中(如v-for循环中)如果我们直接将模板语法编译成正常的HTLM语法是非常困难的。
模板语法先转换成抽象语法树,然后抽象语法树最后会直接变成 渲染函数(h函数)。而 渲染函数 的执行会生成 虚拟节点,虚拟节点 经过 diff等算法,将 虚拟DOM 变成 真实DOM 从而在页面进行展示。 解题思路: 看到这个题目,我们只需要用生活中的常识就可以解决问题,一只手指指向第一个字符,另外一个手指从第二个开始,然会逐一往后与第一个进行比较,如果相同则,第一个手指不移动,如果不相同,第一个手指移动到的第二个手指指向的位置,然后继续上面的操作即可。 这里可以使用双指针,i和j分别代表着两只手指,i=0,j=1 如果 i 和 j 指向的字一样,那么 i 不移动,j 后移 如果 i 和 j 指向的字不一样,此时说明它们之间的字都是连续相同的,让 i 追上 j,j 后移 有了上面的解题思路,我们就看编写代码了: const str = 'aaaaaabbbbbccccccccccccccccccddddd' let i = 0 let j = 1 let max = 0 // 记录出现最多的次数 let strChar = '' // 记录出现最多次数的字符 while(i max) { max = j - i strChar = str[i] } i = j } // 无论是否相同 j都要后移 j++ }总结:其实,指针的问题都是源于我们生活中的常识,快速的找到匹配的结果,一般都可以用指针解题思路来解决问题。 递归 1、试输出斐波那契数列的前10项,即1、1、2、3、5、8、13、21、34、55, 然后请思考,代码是否有大量重复计算?应该如何解决重复计算的问题?解题思路: 通过观察我们可以发现,第一项和第二项均为1,第三项等于前两项相加,后一项等于前两项相加,代码如下: // 斐波那契数列 输出前十项 function fib (n) { return (n == 0 || n==1) ? 1: fib(n-1) + fib(n-2) } for(let i = 0; i { console.log(...args); })找出第一个符号正则条件的下标位置,并且返回一个数组,在全局的情况下会返回全部符合条件的下标位置并组成一个数组返回。 let str = 'ansbsda112fasf578' let num = str.match(/\d/) console.log(num);test 检测字符串是否符合当前正则表达式 找出第一个符号正则条件的下标位置,返回下标,在全局的情况下也只会返回第一个符合条件的下标位置。 let str = 'ansbsda112fasf578' // let num = str.search(/\d/) // 7 let num = str.search(/\d/g) // 7 console.log(num); // 7了解了正则表达式中常用的方法之后,我们正式来讲解一下题目的解题思路: 上面分析我们知道,不能使用递归的方式来解决问题,我们需要通过栈的思想来进行解答,首先需要两个栈stack1和stack2,一个用来存储数字,一个用来存储字符串。 遍历每一个字符串 如果这个字符是数字,那么就将数字压入 stack1栈,把空字符串压入stack2栈, 如果这个字符是字母,那么此时就把stack2栈顶 这一项改为这个字母, 如果这个字符是],那么就将数字从 stack1 栈中弹出,把 stack2的栈顶元素重复 stack1中 弹栈的数字的次数,然后将其从stack2中弹出,拼接到stack2的新栈顶上。
总结:词法分析的时候经常会用到栈的思路去解决问题。 手写 AST 抽象语法树 import parse from "./parse"; var templateStr = ` 你好 A B C ` let ast = parse(templateStr) console.log(ast);
parse()方法 的作用 通过栈思想来生成AST语法树 // index.js import parse from "./parse"; var templateStr = ` 你好 A B C ` let ast = parse(templateStr) console.log(ast); /** * 作用:用来生成AST抽象语法树 * @param {*} templateStr 传入的模板字符串 */ export default function parse(templateStr) { // 指针 var index = 0 // 栈1 存储标签 var stack1 = [] // 栈2 存储文字内容 默认留一项 不用判断stack2结束 var stack2 = [{'children':[]}] // 尾巴 var rest = templateStr // 开始正则 var startRegExp = /^\/ // 结束正则 var endRegExp = /^\/ // 文字正则 var wordErgExp = /^([^\ 0) { stack2[stack2.length - 1].children.push(pop_arr) } } else { new Error(stack1[stack1.length - 1] + '标签没有闭合') } // 指针跳过标签 并包含 所以要+3 index += tag.length + 3 } else if(wordErgExp.test(rest)) { // 检测到文字 let word = rest.match(wordErgExp)[1] // 文字不能是全空 去除空格 if(!/^\s+$/.test(word)) { // 改变此时stack2栈顶元素 stack2[stack2.length - 1].children.push({'text': word, 'type': 3}) } index += word.length } else { index++ } } // console.log(stack2); return stack2[0].children[0] }上面代码的过程,跟栈的算法过程一模一样,如果看不懂的小伙伴,可以再细读栈的例题,再来看这道题,保证你可以很很好的掌握和理解 AST抽象语法树 的生成。当我们往标签中添加类名的时候,其实会报如下图的错误。 import parse from "./parse"; var templateStr = ` 你好 A B C ` let ast = parse(templateStr) console.log(ast);
|
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |